package com.yyfax.pay.third.facade.fuiou;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.TypeReference;
import com.fuiou.mpay.encrypt.DESCoderFUIOU;
import com.fuiou.util.MD5;
import com.google.common.collect.Maps;
import com.yyfax.commons.http.HttpUtil;
import com.yyfax.commons.json.FastJsonUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.common.OpResponse;
import com.yyfax.framework.yyfax.CryptUtil;
import com.yyfax.framework.yyfax.DesensitizationUtil;
import com.yyfax.framework.yyfax.enums.YesNoEnum;
import com.yyfax.pay.common.annotation.ProtocolType;
import com.yyfax.pay.common.constants.FuiouProtocolPayConstant;
import com.yyfax.pay.common.constants.PayConstants;
import com.yyfax.pay.common.enums.*;
import com.yyfax.pay.common.exception.PayException;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.model.to.YYPayApiReq2;
import com.yyfax.pay.common.model.vo.PayRspCodeVO;
import com.yyfax.pay.config.data.service.BankConfigService;
import com.yyfax.pay.config.data.service.MerchantPaymentService;
import com.yyfax.pay.config.model.po.BankConfigPO;
import com.yyfax.pay.order.data.dao.UserPaymentDao;
import com.yyfax.pay.order.data.dao.protocol.ProtocolBindingOrderDao;
import com.yyfax.pay.order.data.dao.protocol.ProtocolOrderDao;
import com.yyfax.pay.order.data.dao.protocol.ProtocolUntieOrderDao;
import com.yyfax.pay.order.data.service.UserAuthService;
import com.yyfax.pay.order.data.service.UserPaymentService;
import com.yyfax.pay.order.model.domain.ProtocolBindingOrderDO;
import com.yyfax.pay.order.model.domain.ProtocolOrderDO;
import com.yyfax.pay.order.model.domain.ProtocolUntieOrderDO;
import com.yyfax.pay.order.model.po.NotifyTaskPO;
import com.yyfax.pay.order.model.po.UserAuthPO;
import com.yyfax.pay.order.model.po.UserPaymentPO;
import com.yyfax.pay.order.model.vo.*;
import com.yyfax.pay.order.service.PayCommonService;
import com.yyfax.pay.quartz.service.PayTaskService;
import com.yyfax.pay.third.model.to.fuiou.*;
import com.yyfax.pay.vo.order.ProtocolCardQueryReq;
import com.yyfax.pay.vo.order.ProtocolCardQueryRsp;
import com.yyfax.pay.vo.order.ProtocolNotifyReq;
import com.yyfax.pay.vo.order.ProtocolPayQueryRsp;

@Service
@ProtocolType(ProtocolEnum.FUIOU_PROTOCOL)
public class FuiouProtocolService implements ProtocolService {

	private Logger logger = LoggerFactory.getLogger(getClass());

	@Resource
	private MerchantPaymentService merchantPaymentService;

	@Resource
	private FuiouProErrorCodeService fuiouProErrorCodeService;

	@Resource
	private UserAuthService userAuthService;

	@Resource
	private UserPaymentDao userPaymentDao;

	@Resource
	private BankConfigService bankConfigService;

	@Resource
	private UserPaymentService userPaymentService;

	@Resource
	private ProtocolBindingOrderDao protocolBindingOrderDao;

	@Resource
	private FuiouProtocolPayConstant fuiouProtocolPayConstant;

	@Resource
	private ProtocolOrderDao protocolOrderDao;

	@Resource
	private PayCommonService payCommonService;

	@Resource
	private PayConstants payConstants;

	@Resource
	private PayTaskService payTaskService;

	@Resource
	private ProtocolUntieOrderDao protocolUntieOrderDao;

	TypeReference<Map<String, String>> strKV = new TypeReference<Map<String, String>>() {
	};

	/**
	 * 请求第三方
	 * 
	 * @author wangjwy
	 * @date 2018/6/15 14:05
	 * @since 1.0.0
	 * @param reqVO, protocolConfig, isDecrypt
	 * @return com.yyfax.pay.third.model.to.fuiou.FuiouProtocolResponseVO
	 * @throws Exception
	 */
	public FuiouProtocolResponseVO postForResponse(FuiouBaseReqVO reqVO, FuiouProtocolPayExt protocolConfig, boolean isDecrypt) {
		final String OP = "FuiouProtocolService.postForResponseVO";
		logger.info(Log.op(OP).msg("富友协议支付发起HTTP请求明文").kv("url", reqVO.getUrl()).kv("params", reqVO.getReqBody()).toString());
		try {
			String result = HttpUtil.postFormDirect(reqVO.getUrl(), reqVO.getActReqBody(), null, null, reqVO.getChartSet(), null, null,
					FuiouProtocolPayConstant.CONNECT_TIMEOUT, FuiouProtocolPayConstant.READ_TIMEOUT);
			if (isDecrypt) {
				result = DESCoderFUIOU.desDecrypt(result, DESCoderFUIOU.getKeyLength8(protocolConfig.getMerchantSecurit()));
			}
			logger.info(Log.op(OP).msg("富友协议支付返回明文").kv("result", result).toString());
			return new FuiouProtocolResponseVO(FuiouProtocolResponseVO.NORMAL, result);
		} catch (SocketTimeoutException e) {
			logger.error(Log.op(OP).msg("富有协议支付请求接口超时").kv("url", reqVO.getUrl()).kv("params", reqVO.getActReqBody()).toString());
			return new FuiouProtocolResponseVO(FuiouProtocolResponseVO.TIMEOUT, null);
		} catch (IOException e) {
			logger.error(Log.op(OP).msg("富有协议支付请求未知异常").kv("url", reqVO.getUrl()).kv("params", reqVO.getActReqBody()).toString());
			return new FuiouProtocolResponseVO(FuiouProtocolResponseVO.TIMEOUT, null);
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("富有协议支付请求解析异常").kv("url", reqVO.getUrl()).kv("params", reqVO.getActReqBody()).toString());
			throw PayExceptionCode.SYS_ERROR.exp();
		}

	}

	public PayRspCodeVO covertToPayRspCode(String code) {
		final String OP = "FuiouProtocolService.covertToPayRspCode";
		if (StringUtils.isBlank(code)) {
			logger.warn(Log.op(OP).msg("转换富友响应码为支付模块响应码，code响应码为空").toString());
			return PayRspCodeVO.newInstance(PayExceptionCode.WARN_UNKNOWN.getCode(), "未知异常，响应码为空");
		}
		// 支付响应信息
		String desc = "";

		// 查询富友响应码对应的文案
		String fuiouResp = "";
		try {
			fuiouResp = fuiouProErrorCodeService.getProperty(code);
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("查询富友响应码对应的提示信息异常").kv("fuiouRespCode", code).toString());
		}

		if (FuiouProRspCodeEnum.isToConfirm(code)) {
			// 请求状态未知，响应码转换为待确认
			desc = StringUtils.isBlank(fuiouResp) ? PayExceptionCode.TO_CONFIRM.getDesc() : fuiouResp;
			return PayRspCodeVO.newInstance(PayExceptionCode.TO_CONFIRM.getCode(), desc);
		}

		// 不是成功、超时、待确认状态都认为是失败
		if (StringUtils.isBlank(fuiouResp)) {
			return PayRspCodeVO.newInstance(PayExceptionCode.ERROR_PROTOCOL_FAIL.getCode(), PayExceptionCode.ERROR_PROTOCOL_FAIL.getDesc());
		}
		return PayRspCodeVO.newInstance(PayExceptionCode.ERROR_OP_EXCEPTION.getCode()).setDesc(fuiouResp);
	}

	public boolean verifySign(String inputStr, String sign, String key) {
		final String OP = "FuiouProtocolService.verifySign";
		String realSign = MD5.MD5Encode(inputStr + "|" + key);
		boolean isSign = false;
		logger.info(Log.op(OP).msg("富友协议支付验签").kv("sing", sign).kv("realSign", realSign).toString());
		if (StringUtils.equals(realSign, sign)) {
			isSign = true;
		}
		return isSign;
	}

	/**
	 * @author buyi
	 * @date 2017-09-02 14:19:55
	 * @since v2.0.0
	 * @param merchantCode
	 * @return
	 * @throws Exception
	 */
	public <T> T getFuiouProtocolConfig(String merchantCode, String paymentCode, String payType, String payMode, Class<T> ext) {
		T t;
		try {
			t = merchantPaymentService.queryByThirdMerchantCodeForExt(merchantCode, paymentCode, payType, payMode, ext);
		} catch (Exception e) {
			logger.error(Log.op("FuiouSignService.getFuiouDepositConfig").msg("查询商户富友协议支付凭证信息异常").kv("merchantCode", merchantCode).toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		if (t == null) {
			throw PayExceptionCode.ERROR_ILL_PARAMETER.expMsg("merchantPayment缺少配置,merchantCode:" + merchantCode);
		}
		return t;
	}

	@Override
	public OpResponse sendMessage(ProtocolBindingOrderDO po) {
		// 获取协议支付扩展信息
		FuiouProtocolPayExt protocolConfig = getFuiouProtocolConfig(po.getMerchantCode(), po.getPaymentCode(), PayTypeEnum.PAY.getValue(),
				PayModeEnum.PROTOCOL_PAY.getValue(), FuiouProtocolPayExt.class);
		// 构建发送验证码请求参数
		FuiouBaseReqVO vo = buildSendMsgReqParam(po, protocolConfig);
		// 请求发送验证码接口
		FuiouProtocolResponseVO resp = postForResponse(vo, protocolConfig, true);
		// 处理请求结果
		OpResponse respon = handleSendMsgResponse(resp, po);
		return respon;
	}

	@Override
	public OpResponse bindProtocol(ProtocolBindingOrderDO po, String messageCode) {
		// 获取协议支付扩展信息
		FuiouProtocolPayExt protocolConfig = getFuiouProtocolConfig(po.getMerchantCode(), po.getPaymentCode(), PayTypeEnum.PAY.getValue(),
				PayModeEnum.PROTOCOL_PAY.getValue(), FuiouProtocolPayExt.class);
		// 构建请求参数
		FuiouBaseReqVO vo = buildBindReqParam(po, protocolConfig, messageCode);
		// 请求第三方接口
		FuiouProtocolResponseVO resp = postForResponse(vo, protocolConfig, true);
		// 处理返回结果
		return handbindRsp(resp, po);
	}

	@Override
	public OpResponse Pay(ProtocolOrderDO po, UserPaymentPO userPaymentPO) {
		// 获取扩展信息
		FuiouProtocolPayExt protocolConfig = getFuiouProtocolConfig(po.getMerchantCode(), po.getPaymentCode(), PayTypeEnum.PAY.getValue(),
				PayModeEnum.PROTOCOL_PAY.getValue(), FuiouProtocolPayExt.class);
		// 构建请求参数
		FuiouBaseReqVO vo = buildPayParam(po, protocolConfig, userPaymentPO);
		// 请求第三方接口
		FuiouProtocolResponseVO respVO = postForResponse(vo, protocolConfig, true);
		// ProtocolPayRsp protocolPayRsp = new ProtocolPayRsp();
		return handlePayResult(po, protocolConfig, respVO);
	}

	@Override
	public OpResponse untieProtocol(ProtocolUntieOrderDO po, UserPaymentPO userPaymentPO) {
		// 获取协议支付扩展信息
		FuiouProtocolPayExt protocolConfig = getFuiouProtocolConfig(po.getMerchantCode(), PaymentEnum.FUIOU_PROTOCOL_PAY.getValue(),
				PayTypeEnum.PAY.getValue(), PayModeEnum.PROTOCOL_PAY.getValue(), FuiouProtocolPayExt.class);
		// 构建发送解绑请求参数
		FuiouBaseReqVO vo = buildUntieReqParam(po, protocolConfig);
		// 发送解绑请求
		FuiouProtocolResponseVO respVo = postForResponse(vo, protocolConfig, true);
		// 处理结果
		return handUntieRsp(respVo, po, userPaymentPO);
	}

	/**
	 * 处理解绑返回
	 *
	 * @author wangjwy
	 * @date 2018/6/15 15:35
	 * @since 2.2.0
	 * @param respVo, po, userPaymentPO
	 * @return com.yyfax.framework.common.OpResponse
	 * @throws Exception
	 */
	private OpResponse handUntieRsp(FuiouProtocolResponseVO respVo, ProtocolUntieOrderDO po, UserPaymentPO userPaymentPO) {
		final String OP = "ProtocolUntieServiceImpl.handUntieRsp";
		OpResponse response = new OpResponse();
		if (FuiouProtocolResponseVO.TIMEOUT.equals(respVo.getResult())) {
			logger.warn(Log.op(OP).msg("请求解绑协议卡接口超时,保存超时查询任务").toString());
			// //保存超时查询任务
			// saveQueryTask(po);
			throw PayExceptionCode.WARN_REQ_TIME_OUT.exp();
		}
		String result = respVo.getContent();
		FuiouProUnbindRsp unbindRsp = FuiouProUnbindRsp.fromXml(result);
		int code;
		String desc = "";
		if (FuiouProRspCodeEnum.isToConfirm(unbindRsp.getRespCode())) {
			logger.warn(Log.op(OP).msg("请求解绑协议卡返回待确认").kv("respVo", respVo).kv("po", po).toString());
			code = PayExceptionCode.PROCESSING.getCode();
			protocolUntieOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.DEALING.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), code, unbindRsp.getRespDesc());
			desc = unbindRsp.getRespDesc();
		} else if (!FuiouProRspCodeEnum.SUCCESS.getValue().equals(unbindRsp.getRespCode())) {
			logger.warn(Log.op(OP).msg("解绑协议卡返回失败").kv("respVo", respVo).kv("po", po).kv("响应码", unbindRsp.getRespCode())
					.kv("描述", unbindRsp.getRespDesc()).toString());
			code = PayExceptionCode.ERROR_PROTOCOL_FAIL.getCode();
			protocolUntieOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.FAIL.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), code, unbindRsp.getRespDesc());
			throw new PayException(PayExceptionCode.ERROR_UNBIND_EXCEPTION.getCode(), unbindRsp.getRespDesc());
		} else {
			code = PayExceptionCode.SUCCESS.getCode();
			logger.info(Log.op(OP).msg("解绑协议卡返回成功").kv("respVo", respVo).kv("po", po).toString());
			protocolUntieOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.SUCCESS.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), code, unbindRsp.getRespDesc());

			// 更新用户支付扩展信息
			userPaymentPO.setState(YesNoEnum.NO.getValue());
			userPaymentDao.update(userPaymentPO);
			desc = unbindRsp.getRespDesc();
		}

		response.setCode(code);
		response.setDisplay(desc);
		return response;

	}

	@Override
	public OpResponse checkResult(ProtocolOrderDO po) {
		// 获取扩展信息
		FuiouProtocolPayExt protocolCfg = getFuiouProtocolConfig(po.getMerchantCode(), po.getPaymentCode(), PayTypeEnum.PAY.getValue(),
				PayModeEnum.PROTOCOL_PAY.getValue(), FuiouProtocolPayExt.class);
		// 构建请求参数
		FuiouBaseReqVO vo = buildReqVo(po, protocolCfg);

		FuiouProtocolResponseVO respVO = postForResponse(vo, protocolCfg, false);

		return handleResult(po, protocolCfg, respVO);
	}

	/**
	 * 构建解绑请求
	 *
	 * @author wangjwy
	 * @date 2018/6/15 15:35
	 * @since 2.2.0
	 * @param untieOrderDO, protocolConfig
	 * @return com.yyfax.pay.third.model.to.fuiou.FuiouBaseReqVO
	 * @throws Exception
	 */
	private FuiouBaseReqVO buildUntieReqParam(ProtocolUntieOrderDO untieOrderDO, FuiouProtocolPayExt protocolConfig) {
		final String OP = "ProtocolUntieServiceImpl.buildUntieReqParam";
		FuiouBaseReqVO reqVO = new FuiouBaseReqVO();
		ProtocolUntieVO xml = new ProtocolUntieVO();
		xml.setMerchantCode(protocolConfig.getMerchantId());
		xml.setProtocolCode(untieOrderDO.getProtocolCode());
		xml.setUserId(untieOrderDO.getUserAuthId());
		xml.setVersion(protocolConfig.getVersion());
		StringBuffer sb = new StringBuffer();
		sb.append(xml.getVersion()).append("|").append(xml.getMerchantCode()).append("|").append(xml.getUserId()).append("|")
				.append(xml.getProtocolCode()).append("|").append(protocolConfig.getMerchantSecurit());
		xml.setSign(MD5.MD5Encode(sb.toString()));
		HashMap<String, String> map = Maps.newHashMap();
		map.put(FuiouProtocolPayConstant.MCHNTCD, xml.getMerchantCode());
		try {
			map.put(FuiouProtocolPayConstant.APIFMS,
					DESCoderFUIOU.desEncrypt(xml.toXml(), DESCoderFUIOU.getKeyLength8(protocolConfig.getMerchantSecurit())));
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("协议解绑加密请求参数异常").toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		reqVO.setReqBody(xml.toXml());
		reqVO.setUrl(protocolConfig.getUnBindUrl());
		reqVO.setActReqBody(map);
		reqVO.setConnectTimeOut(protocolConfig.getConnectTimeout());
		reqVO.setChartSet(FuiouProtocolPayConstant.ENCOCING);
		return reqVO;

	}

	/**
	 * 处理支付返回结果
	 *
	 * @author wangjwy
	 * @date 2018/6/19 9:19
	 * @since 2.2.0
	 * @param po, protocolCfg, respVO
	 * @return com.yyfax.framework.common.OpResponse
	 * @throws Exception
	 */
	private OpResponse handleResult(ProtocolOrderDO po, FuiouProtocolPayExt protocolCfg, FuiouProtocolResponseVO respVO) {
		final String OP = "ProtocolPayServiceImpl.handleResult";
		OpResponse response = OpResponse.success();
		if (FuiouProtocolResponseVO.TIMEOUT.equals(respVO.getResult())) {
			logger.warn(Log.op(OP).msg("请求协议支付查询接口超时").kv("po", po).kv("respVo", respVO).toString());
			throw PayExceptionCode.WARN_REQ_TIME_OUT.exp();
		}

		String content = respVO.getContent();
		FuiouProtocolPayQueryRsp payRsp = FuiouProtocolPayQueryRsp.fromXml(content);
		StringBuffer sb = new StringBuffer();
		sb.append(payRsp.getVersion()).append("|").append(payRsp.getRespCode()).append("|").append(payRsp.getRespDesc()).append("|")
				.append(payRsp.getBusiId());
		boolean isSign = verifySign(sb.toString(), payRsp.getSign(), protocolCfg.getMerchantSecurit());
		// 验签
		if (!isSign) {
			logger.error(Log.op(OP).msg("富友协议支付查询订单返回验签失败").kv("result", content).kv("po", po).toString());
			// protocolOrderDao.modifyState(po.getBusiId(),Integer.valueOf(OrderStateEnum.FAIL.getValue()),Integer.valueOf(OrderStateEnum.DEALING.getValue()),PayExceptionCode.ERROR_SIGN_FAIL.getCode(),payRsp.getRespDesc(),
			// po.getOrderId());
			throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
		}

		// 富友提供的中间状态码
		if (FuiouProRspCodeEnum.isToConfirm(payRsp.getRespCode())) {
			logger.info(Log.op(OP).msg("富友协议支付查询订单返回中间态").kv("result", content).kv("po", po).toString());
			protocolOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.DEALING.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), PayExceptionCode.TO_CONFIRM.getCode(), payRsp.getRespDesc(), po.getOrderId());
			po.setState(Integer.valueOf(OrderStateEnum.DEALING.getValue()));
			po.setRespCode(PayExceptionCode.TO_CONFIRM.getCode());
			po.setRespDesc(payRsp.getRespDesc());
			protocolOrderDao.modifyState(po.getBusiId(), po.getState(), Integer.valueOf(OrderStateEnum.DEALING.getValue()),
					PayExceptionCode.TO_CONFIRM.getCode(), po.getRespDesc(), po.getOrderId());
		} else if (StringUtils.equals(FuiouProRspCodeEnum.SUCCESS.getValue(), payRsp.getRespCode())) {
			logger.info(Log.op(OP).msg("富友协议支付查询订单返回成功").kv("busiId", po.getBusiId()).kv("result", content).toString());
			// protocolOrderDao.modifyState(po.getBusiId(),Integer.valueOf(OrderStateEnum.SUCCESS.getValue()),Integer.valueOf(OrderStateEnum.DEALING.getValue()),PayExceptionCode.SUCCESS.getCode(),payRsp.getRespDesc(),
			// po.getOrderId());
			// code = PayExceptionCode.SUCCESS.getCode();
			po.setState(Integer.valueOf(OrderStateEnum.SUCCESS.getValue()));
			po.setRespCode(PayExceptionCode.SUCCESS.getCode());
			po.setRespDesc(payRsp.getRespDesc());
			protocolOrderDao.modifyState(po.getBusiId(), po.getState(), Integer.valueOf(OrderStateEnum.DEALING.getValue()),
					PayExceptionCode.SUCCESS.getCode(), po.getRespDesc(), po.getOrderId());
		} else {
			logger.info(Log.op(OP).msg("富友协议支付查询订单返回失败").kv("busiId", po.getBusiId()).toString());
			po.setState(Integer.valueOf(OrderStateEnum.FAIL.getValue()));
			po.setRespCode(PayExceptionCode.ERROR_PROTOCOL_FAIL.getCode());
			po.setRespDesc(payRsp.getRespDesc());
			protocolOrderDao.modifyState(po.getBusiId(), po.getState(), Integer.valueOf(OrderStateEnum.DEALING.getValue()),
					PayExceptionCode.ERROR_PROTOCOL_FAIL.getCode(), po.getRespDesc(), po.getOrderId());
		}
		response.setContent(buildProtocolQueryRsp(po));
		return response;
	}

	/**
	 * 构建响应
	 *
	 * @author wangjwy
	 * @date 2018/6/19 10:55
	 * @since 2.2.0
	 * @param po
	 * @return com.yyfax.pay.vo.order.ProtocolPayQueryRsp
	 * @throws Exception
	 */
	private ProtocolPayQueryRsp buildProtocolQueryRsp(ProtocolOrderDO po) {
		ProtocolPayQueryRsp rsp = new ProtocolPayQueryRsp();
		rsp.setAmount(po.getAmount());
		rsp.setBusiId(po.getBusiId());
		rsp.setMerchantCode(po.getMerchantCode());
		rsp.setOrderId(po.getOrderId());
		rsp.setBusiId(po.getBusiId());
		rsp.setOrderTime(po.getOrderTime());
		rsp.setProtocolCode(po.getProtocolCode());
		rsp.setRespCode(po.getRespCode());
		rsp.setRespDesc(po.getRespDesc());
		rsp.setState(po.getState());
		rsp.setUserId(po.getUserId());
		return rsp;
	}

	/**
	 * 构建第三方支付请求
	 *
	 * @author wangjwy
	 * @date 2018/6/19 10:55
	 * @since 2.2.0
	 * @param po, protocolCfg
	 * @return com.yyfax.pay.third.model.to.fuiou.FuiouBaseReqVO
	 * @throws Exception
	 */
	private FuiouBaseReqVO buildReqVo(ProtocolOrderDO po, FuiouProtocolPayExt protocolCfg) {
		final String OP = "ProtocolPayServiceImpl.buildReqVo";
		FuiouBaseReqVO reqVO = new FuiouBaseReqVO();
		ProtocolPayQueryVO xml = new ProtocolPayQueryVO();
		xml.setBusiId(po.getBusiId());
		xml.setMerchantCode(protocolCfg.getMerchantId());
		xml.setVersion(protocolCfg.getQueryVersion());
		StringBuffer sb = new StringBuffer();
		sb.append(xml.getVersion()).append("|").append(xml.getMerchantCode()).append("|").append(xml.getBusiId()).append("|")
				.append(protocolCfg.getMerchantSecurit());
		xml.setSign(MD5.MD5Encode(sb.toString()));
		HashMap<String, String> map = Maps.newHashMap();
		try {
			// map.put("FM",DESCoderFUIOU.desEncrypt(xml.toXml(), DESCoderFUIOU.getKeyLength8(protocolCfg.getMerchantSecurit())));
			map.put(FuiouProtocolPayConstant.FM, xml.toXml());
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("协议支付加密请求失败").kv("ProtocolOrderDO", po).toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		reqVO.setActReqBody(map);
		reqVO.setReqBody(xml.toXml());
		reqVO.setUrl(protocolCfg.getCheckResultUrl());
		reqVO.setChartSet(FuiouProtocolPayConstant.ENCOCING);
		reqVO.setConnectTimeOut(protocolCfg.getConnectTimeout());
		return reqVO;
	}

	/**
	 * 处理交易结果
	 *
	 * @author wangjwy
	 * @date 2018/6/19 10:56
	 * @since 2.2.0
	 * @param po, protocolPayRsp, protocolConfig, respVO
	 * @return com.yyfax.framework.common.OpResponse
	 * @throws Exception
	 */
	private OpResponse handlePayResult(ProtocolOrderDO po, FuiouProtocolPayExt protocolConfig, FuiouProtocolResponseVO respVO) {
		final String OP = "ProtocolPayServiceImpl.handlePayResult";
		OpResponse response = OpResponse.success();
		int code;
		String desc;
		// 处理请求结果,更新订单状态
		if (FuiouProtocolResponseVO.TIMEOUT.equals(respVO.getResult())) {
			logger.warn(Log.op(OP).msg("请求协议支付接口超时").kv("busiId", po.getBusiId()).kv("orderId", po.getOrderId()).toString());
			try {
				String startTime = DateUtil.datetime2Str(DateUtil.addMinute(new Date(), payConstants.getPayQueryMinuteDelay()));
				payCommonService.saveQueryTask(po.getMerchantCode(), po.getOrderId(), null, QueryTaskTypeEnum.PROTOCOL_PAY, po.getBusiId(),
						po.getPaymentCode(), startTime, null, payConstants.getQueryTaskMax(), "");
			} catch (Exception e) {
				logger.warn(Log.op(OP).msg("生成协议支付超时查询任务异常").kv("busiId", po.getBusiId()).toString(), e);
			}
			throw PayExceptionCode.WARN_REQ_TIME_OUT.exp();
		}

		String content = respVO.getContent();
		FuiouProtocolPayRsp payRsp = FuiouProtocolPayRsp.fromXml(content);
		StringBuffer sb = new StringBuffer();
		sb.append(payRsp.getType()).append("|").append(payRsp.getVersion()).append("|").append(payRsp.getRespCode()).append("|")
				.append(payRsp.getMerchantCode()).append("|").append(payRsp.getMerchantOrderId()).append("|")
				.append(payRsp.getThirdOrderId() == null ? "" : payRsp.getThirdOrderId()).append("|")
				.append(payRsp.getAmt() == null ? "" : payRsp.getAmt()).append("|").append(payRsp.getCardNo() == null ? "" : payRsp.getCardNo());
		boolean isSign = verifySign(sb.toString(), payRsp.getSign(), protocolConfig.getMerchantSecurit());
		// 验签
		if (!isSign) {
			logger.error(Log.op(OP).msg("富友协议支付返回验签失败").kv("result", content).toString());
			throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
		}
		// 富友提供的中间状态码
		if (FuiouProRspCodeEnum.isToConfirm(payRsp.getRespCode())) {
			code = PayExceptionCode.TO_CONFIRM.getCode();
			logger.info(Log.op(OP).msg("富友协议支付订单返回中间态").kv("result", content).kv("po", po).toString());
			protocolOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.DEALING.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), code, payRsp.getRespDesc(), payRsp.getThirdOrderId());
		} else if (StringUtils.equals(FuiouProRspCodeEnum.SUCCESS.getValue(), payRsp.getRespCode())) {
			code = PayExceptionCode.SUCCESS.getCode();
			logger.info(Log.op(OP).msg("富友协议支付返回成功").kv("busiId", po.getBusiId()).toString());
			protocolOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.SUCCESS.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), code, payRsp.getRespDesc(), payRsp.getThirdOrderId());
		} else {
			code = PayExceptionCode.ERROR_PROTOCOL_FAIL.getCode();
			logger.info(Log.op(OP).msg("富友协议支付返回订单失败").kv("busiId", po.getBusiId()).toString());
			protocolOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.FAIL.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), code, payRsp.getRespDesc(), payRsp.getThirdOrderId());
		}
		desc = payRsp.getRespDesc();
		// protocolPayRsp.setBusiId(po.getBusiId());
		response.setCode(code);
		response.setDisplay(desc);
		// response.setContent(protocolPayRsp);
		return response;
	}

	@Override
	public OpResponse queryProtocol(ProtocolCardQueryReq params, String merchantCode, String userAuthId, UserPaymentPO userPaymentPO) {
		// 查询支付通道扩展信息
		FuiouProtocolPayExt protocolCfg = getFuiouProtocolConfig(merchantCode, params.getPaymentCode(), PayTypeEnum.PAY.getValue(),
				PayModeEnum.PROTOCOL_PAY.getValue(), FuiouProtocolPayExt.class);
		// 构建请求参数
		FuiouBaseReqVO vo = buildQueryCardReq(userAuthId, protocolCfg);
		// 发送请求
		FuiouProtocolResponseVO respVO = postForResponse(vo, protocolCfg, true);

		ProtocolCardQueryRsp rsp = handCardQueryRsp(merchantCode, params, userPaymentPO, respVO, userAuthId);
		OpResponse response = new OpResponse();
		response.setContent(rsp);
		return response;
	}

	@Override
	public void handNotify(ProtocolPayNotifyReq req, ProtocolOrderDO po, UserPaymentPO userPaymentPO) {
		final String OP = "FuiouProtocolService.handNotify";
		FuiouProtocolPayExt protocolCfg = getFuiouProtocolConfig(po.getMerchantCode(), po.getPaymentCode(), PayTypeEnum.PAY.getValue(),
				PayModeEnum.PROTOCOL_PAY.getValue(), FuiouProtocolPayExt.class);
		StringBuffer sb = new StringBuffer();
		sb.append(req.getType()).append("|").append(req.getVersion()).append("|").append(req.getResponsecode()).append("|").append(req.getMchntcd())
				.append("|").append(req.getMchntorderid()).append("|").append(req.getOrderid() == null ? "" : req.getOrderid()).append("|")
				.append(req.getAmt() == null ? "" : req.getAmt()).append("|").append(req.getBankcard() == null ? "" : req.getBankcard());
		boolean isSign = verifySign(sb.toString(), req.getSign(), protocolCfg.getMerchantSecurit());
		if (!isSign) {
			logger.error(Log.op(OP).msg("协议支付异步通知验签失败").kv("req", req).toString());
			throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
		}

		if (null != req.getAmt() && po.getAmount().longValue() != req.getAmt().longValue()) {
			logger.error(Log.op(OP).msg("富友协议支付异步通知数据异常,需要人工介入").kv("busiId", po.getBusiId()).kv("[yyfax]amt", po.getAmount())
					.kv("[fuiou]amt", req.getAmt()).toString());
			// throw PayExceptionCode.ERROR_DATA_EXCEPTION.exp();
		}

		int code;
		String desc = req.getResponsemsg();
		Integer state;
		// 异步通知返回成功
		if (FuiouProRspCodeEnum.SUCCESS.getValue().equals(req.getResponsecode())) {
			logger.info(Log.op(OP).msg("收到富友协议支付异步通知订单结果成功").kv("busiId", req.getMchntorderid()).kv("thirdOrderId", req.getOrderid()).toString());
			code = PayExceptionCode.SUCCESS.getCode();
			state = (Integer.valueOf(OrderStateEnum.SUCCESS.getValue()));
		} else {
			logger.warn(Log.op(OP).msg("收到富友协议支付异步通知订单结果失败").kv("busiId", req.getMchntorderid()).kv("thirdOrderId", req.getOrderid()).toString());
			code = PayExceptionCode.ERROR_PROTOCOL_FAIL.getCode();
			state = (Integer.valueOf(OrderStateEnum.FAIL.getValue()));
		}

		// 最终交易结果状态预警
		if (OrderStateEnum.isResult(po.getState().toString()) && po.getState().intValue() != state.intValue()) {
			logger.error(Log.op(OP).msg("[预警]订单状态已为终态,且异步通知状态和订单状态不一致,需要人工介入").kv("req", req).toString());
		} else {
			protocolOrderDao.modifyState(po.getBusiId(), state, Integer.valueOf(OrderStateEnum.DEALING.getValue()), code, desc, req.getOrderid());
			// 异步通知业务
			generateNotifyTask(po.getBusiId(), po.getOrderId(), state, code, desc, po.getMerchantCode(), po.getPayNotifyUrl());
		}
	}

	/**
	 * 生成异步通知任务
	 *
	 * @author wangjwy
	 * @date 2018/6/15 15:56
	 * @since 2.2.0
	 * @param busiId, orderId, state, respCode, respdesc, merchantCode, url
	 * @return void
	 * @throws Exception
	 */
	private void generateNotifyTask(String busiId, String orderId, Integer state, Integer respCode, String respdesc, String merchantCode,
			String url) {
		final String OP = "ProtocolPayServiceImpl.generateNotifyTask";
		logger.info(Log.op(OP).msg("开始生成异步通知任务").kv("busiId", busiId).kv("orderId", orderId).toString());
		try {
			ProtocolNotifyReq params = new ProtocolNotifyReq();
			params.setOrderId(orderId);
			params.setRspCode(respCode);
			params.setState(state);
			params.setRspMsg(respdesc);
			YYPayApiReq2<ProtocolNotifyReq> req = new YYPayApiReq2<>();
			req.setMerchantCode(merchantCode);
			req.setSign(payCommonService.getSign(merchantCode, params));
			req.setParams(params);
			NotifyTaskPO notifyTaskPO = buildNotifyTask(merchantCode, orderId, busiId, url, FastJsonUtil.toJson(req), DateUtil.getCurrentDateTime(),
					null);
			payTaskService.notifyTask(notifyTaskPO);
			logger.info(Log.op(OP).msg("生成异步通知任务完成").kv("notifyTaskPO", notifyTaskPO).toString());
			int iCount = protocolOrderDao.modifyNotifyState(busiId, YesNoEnum.NO.getValue(), YesNoEnum.YES.getValue());
			if (iCount != 1) {
				logger.error(Log.op(OP).msg("修改协议支付异步通知状态未命中,收到多次通知|订单不存在").kv("req", req).kv("busiId", busiId).toString());
			}
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("封装同步结果异步通知任务异常").kv("orderId", orderId).kv("busiId", busiId).kv("merchantCode", merchantCode).toString(), e);
		}
	}

	/**
	 * 构建通知任务
	 *
	 * @author wangjwy
	 * @date 2018/6/19 10:53
	 * @since 2.2.0
	 * @param merchantCode, orderId, busiId, url, param, startTime, endTime
	 * @return com.yyfax.pay.order.model.po.NotifyTaskPO
	 * @throws Exception
	 */
	private NotifyTaskPO buildNotifyTask(String merchantCode, String orderId, String busiId, String url, String param, String startTime,
			String endTime) {
		NotifyTaskPO po = new NotifyTaskPO();
		po.setState(TaskStateEnum.ACTIVE.getValue());
		po.setOptNo(0);
		po.setEndTime(endTime);
		po.setMaxNo(payConstants.getMaxNo());
		po.setMerchantCode(merchantCode);
		po.setNotifyUrl(url);
		po.setOrderId(orderId);
		po.setStartTime(startTime);
		po.setTradeOrderId(busiId);
		po.setType(NotifyTaskTypeEnum.PROTOCOL_PAY.getValue());
		po.setReqContent(param);
		return po;
	}

	/**
	 * 构建请求参数
	 *
	 * @author wangjwy
	 * @date 2018/6/7 9:55
	 * @since 2.2.0
	 * @param po, protocolConfig
	 * @return com.yyfax.pay.third.model.to.fuiou.FuiouBaseReqVO
	 * @throws Exception
	 */
	private FuiouBaseReqVO buildSendMsgReqParam(ProtocolBindingOrderDO po, FuiouProtocolPayExt protocolConfig) {
		final String OP = "ProtocolBindServiceImpl.buildReqParam";
		SimpleDateFormat spdf = new SimpleDateFormat(FuiouProtocolPayConstant.pattern);
		FuiouBaseReqVO vo = new FuiouBaseReqVO();
		ProtocolBindSendMsgVO xml = new ProtocolBindSendMsgVO();
		xml.setVersion(protocolConfig.getVersion());
		xml.setAccountName(po.getAccountName());
		try {
			xml.setCardNo(CryptUtil.decrypt(po.getCardNoCip()));
			xml.setIdNo(CryptUtil.decrypt(po.getIdNoCip()));
		} catch (Exception e) {
			logger.warn(Log.op(OP).msg("解密银行卡或身份证失败").kv("cardNo", po.getCardNoCip()).kv("idNo", po.getIdNoCip()).toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		xml.setCertif_tp(FuiouProtocolPayConstant.CERTIFYTYPE);
		xml.setMerchantCode(protocolConfig.getMerchantId());
		xml.setOrderDate(spdf.format(po.getOrderTime()));
		xml.setOrderId(po.getBusiId());
		xml.setPhone(po.getPhone());
		xml.setUserId(po.getUserAuthId());
		StringBuffer sb = new StringBuffer();
		sb.append(xml.getVersion()).append("|").append(xml.getOrderId()).append("|").append(xml.getMerchantCode()).append("|").append(xml.getUserId())
				.append("|").append(xml.getAccountName()).append("|").append(xml.getCardNo()).append("|").append(xml.getCertif_tp()).append("|")
				.append(xml.getIdNo()).append("|").append(xml.getPhone()).append("|").append(protocolConfig.getMerchantSecurit());
		xml.setSign(MD5.MD5Encode(sb.toString()));
		HashMap<String, String> map = Maps.newHashMap();
		map.put(FuiouProtocolPayConstant.MCHNTCD, xml.getMerchantCode());
		try {
			map.put(FuiouProtocolPayConstant.APIFMS,
					DESCoderFUIOU.desEncrypt(xml.toXml(), DESCoderFUIOU.getKeyLength8(protocolConfig.getMerchantSecurit())));
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("富友协议支付加密请求参数异常").kv("ProtocolBindingOrderDO", po).toString(), e);
			e.printStackTrace();
		}
		vo.setUrl(protocolConfig.getBindMsgUrl());
		vo.setReqBody(xml.toXml());
		vo.setActReqBody(map);
		vo.setChartSet(FuiouProtocolPayConstant.ENCOCING);
		return vo;
	}

	/**
	 * 处理返回
	 *
	 * @author wangjwy
	 * @date 2018/6/7 9:55
	 * @since 2.2.0
	 * @param resp, po
	 * @return void
	 * @throws Exception
	 */
	private OpResponse handleSendMsgResponse(FuiouProtocolResponseVO resp, ProtocolBindingOrderDO po) {
		final String OP = "ProtocolBindServiceImpl.handleSendMsgResponse";
		OpResponse rsp = OpResponse.success();
		if (FuiouProtocolResponseVO.TIMEOUT.equals(resp.getResult())) {
			logger.error(Log.op(OP).msg("请求富友协议发送验证码接口超时").kv("resp", resp).kv("po", po).toString());
			throw PayExceptionCode.WARN_REQ_TIME_OUT.exp();
		}

		String result = resp.getContent();
		BindMsgRsp bindMsgRsp = BindMsgRsp.fromXml(result);

		if (!FuiouProRspCodeEnum.SUCCESS.getValue().equals(bindMsgRsp.getRespCode())) {
			PayRspCodeVO vo = covertToPayRspCode(bindMsgRsp.getRespCode());
			logger.error(Log.op(OP).msg("协议绑卡请求验证码失败").kv("resp", resp).kv("po", po).kv("响应码", bindMsgRsp.getRespCode())
					.kv("描述", bindMsgRsp.getRespMsg()).toString());
			protocolBindingOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.FAIL.getValue()),
					Integer.valueOf(OrderStateEnum.INI.getValue()), vo.getCode(), vo.getDesc(), null);
			throw PayExceptionCode.ERROR_PROTOCOL_SENDMSG.exp();
		}
		return rsp;
		// protocolBindingOrderDao.modifyState(po.getBusiId(),Integer.valueOf(OrderStateEnum.DEALING.getValue()),Integer.valueOf(OrderStateEnum.INI.getValue()),PayExceptionCode.DEALING.getCode(),bindMsgRsp.getRespMsg(),null);
	}

	/**
	 * 构建请求绑卡订单
	 *
	 * @author wangjwy
	 * @date 2018/6/7 10:39
	 * @since 2.2.0
	 * @param po, protocolConfig
	 * @return com.yyfax.pay.third.model.to.fuiou.FuiouBaseReqVO
	 * @throws Exception
	 */
	private FuiouBaseReqVO buildBindReqParam(ProtocolBindingOrderDO po, FuiouProtocolPayExt protocolConfig, String msgCode) {
		final String OP = "ProtocolBindServiceImpl.buildBindReqParam";
		SimpleDateFormat spdf = new SimpleDateFormat(FuiouProtocolPayConstant.pattern);
		FuiouBaseReqVO fuiouBaseReqVO = new FuiouBaseReqVO();
		ProtocolBindVO xml = new ProtocolBindVO();
		xml.setVersion(protocolConfig.getVersion());
		xml.setAccountName(po.getAccountName());
		try {
			xml.setCardNo(CryptUtil.decrypt(po.getCardNoCip()));
			xml.setIdNo(CryptUtil.decrypt(po.getIdNoCip()));
		} catch (Exception e) {
			logger.warn(Log.op(OP).msg("解密银行卡或身份证失败").kv("cardNo", po.getCardNoCip()).kv("idNo", po.getIdNoCip()).toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		xml.setCertif_tp(FuiouProtocolPayConstant.CERTIFYTYPE);
		xml.setMerchantCode(protocolConfig.getMerchantId());
		xml.setMsgCode(msgCode);
		xml.setOrderDate(spdf.format(po.getOrderTime()));
		xml.setOrderId(po.getBusiId());
		xml.setPhone(po.getPhone());
		xml.setUserId(po.getUserAuthId());
		StringBuffer sb = new StringBuffer();
		sb.append(xml.getVersion()).append("|").append(xml.getOrderId()).append("|").append(xml.getMerchantCode()).append("|").append(xml.getUserId())
				.append("|").append(xml.getAccountName()).append("|").append(xml.getCardNo()).append("|").append(xml.getCertif_tp()).append("|")
				.append(xml.getIdNo()).append("|").append(xml.getPhone()).append("|").append(xml.getMsgCode()).append("|")
				.append(protocolConfig.getMerchantSecurit());
		xml.setSign(MD5.MD5Encode(sb.toString()));
		HashMap<String, String> map = Maps.newHashMap();
		map.put(FuiouProtocolPayConstant.MCHNTCD, xml.getMerchantCode());
		try {
			map.put(FuiouProtocolPayConstant.APIFMS,
					DESCoderFUIOU.desEncrypt(xml.toXml(), DESCoderFUIOU.getKeyLength8(protocolConfig.getMerchantSecurit())));
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("富友协议支付请求报文加密异常").kv("ProtocolBindingOrderDO", po).toString());
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		fuiouBaseReqVO.setUrl(protocolConfig.getBindCommitUrl());
		fuiouBaseReqVO.setReqBody(xml.toXml());
		fuiouBaseReqVO.setActReqBody(map);
		fuiouBaseReqVO.setChartSet(FuiouProtocolPayConstant.ENCOCING);
		return fuiouBaseReqVO;
	}

	/**
	 * 处理协议绑卡返回
	 *
	 * @author wangjwy
	 * @date 2018/6/15 14:09
	 * @since 2.2.0
	 * @param resp, po
	 * @return void
	 * @throws Exception
	 */
	private OpResponse handbindRsp(FuiouProtocolResponseVO resp, ProtocolBindingOrderDO po) {
		final String OP = "ProtocolBindServiceImpl.handbindRsp";
		OpResponse response = new OpResponse();
		if (FuiouProtocolResponseVO.TIMEOUT.equals(resp.getResult())) {
			logger.error(Log.op(OP).msg("请求接口超时").kv("resp", resp).kv("po", po).toString());
			throw PayExceptionCode.WARN_REQ_TIME_OUT.exp();
		}

		String result = resp.getContent();
		BindRsp bindRsp = BindRsp.fromXml(result);

		if (FuiouProRspCodeEnum.ERROR_VERIFY_CODE_OR_EXPIRE.getValue().equals(bindRsp.getRespCode())) {
			logger.warn(Log.op(OP).msg("验证码错误或者已过期").kv("rsp", bindRsp).kv("po", po).toString());
			protocolBindingOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.INI.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), PayExceptionCode.VERIFY_CODE_INVALID.getCode(), bindRsp.getRespMsg(), null);
			throw PayExceptionCode.VERIFY_CODE_INVALID.exp();
		}
		// 不是成功状态
		if (FuiouProRspCodeEnum.isToConfirm(bindRsp.getRespCode())) {
			logger.warn(Log.op(OP).msg("富友协议绑卡返回中间状态").kv("rsp", bindRsp).kv("po", po).toString());
			protocolBindingOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.DEALING.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), PayExceptionCode.DEALING.getCode(), bindRsp.getRespMsg(), null);
			response.setCode(PayExceptionCode.DEALING.getCode());
			response.setDisplay(bindRsp.getRespMsg());
		} else if (!FuiouProRspCodeEnum.SUCCESS.getValue().equals(bindRsp.getRespCode())) {
			PayRspCodeVO vo = covertToPayRspCode(bindRsp.getRespCode());
			logger.warn(Log.op(OP).msg("富友协议绑卡失败").kv("po", po).kv("响应码", bindRsp.getRespCode()).kv("描述", bindRsp.getRespMsg()).toString());
			protocolBindingOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.FAIL.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), vo.getCode(), vo.getDesc(), null);
			throw new PayException(PayExceptionCode.ERROR_PROTOCOL_FAIL.getCode(), bindRsp.getRespMsg());
		}
		UserPaymentPO userPaymentPO = null;
		try {
			UserAuthPO uap = userAuthService.queryByUserIdAndMerchantCode(po.getUserId(), po.getMerchantCode());
			if (null == uap) {
				logger.error(Log.op(OP).msg("查询用户支付认证信息异常").kv("userId", po.getUserId()).kv("merchantCode", po.getMerchantCode()).toString());
				throw PayExceptionCode.WARN_UNKNOWN.exp();
			}
			userPaymentPO = buildUserPaymentPo(DesensitizationUtil.convertBankCard(CryptUtil.decrypt(po.getCardNoCip())), po.getCardNoCip(),
					po.getUserId(), po.getPhone(), po.getMerchantCode(), po.getBankCode(), bindRsp.getProtocolCode(), uap.getUserAuthId());
			userPaymentService.saveOrUpdate(userPaymentPO);
			protocolBindingOrderDao.modifyState(po.getBusiId(), Integer.valueOf(OrderStateEnum.SUCCESS.getValue()),
					Integer.valueOf(OrderStateEnum.DEALING.getValue()), PayExceptionCode.SUCCESS.getCode(), bindRsp.getRespMsg(),
					bindRsp.getProtocolCode());
			response.setCode(PayExceptionCode.SUCCESS.getCode());
			response.setDisplay(bindRsp.getRespMsg());
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("更新用户支付扩展信息失败").kv("userPaymentPo", userPaymentPO).toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		return response;
	}

	/**
	 * 构建用户支付扩展信息
	 *
	 * @author wangjwy
	 * @date 2018/6/19 10:52
	 * @since 2.2.0
	 * @param desensCardNo, cardNoCip, userId, phone, merchantCode, bankCode, protocolCode, userAuthId
	 * @return com.yyfax.pay.order.model.po.UserPaymentPO
	 * @throws Exception
	 */
	private UserPaymentPO buildUserPaymentPo(String desensCardNo, String cardNoCip, String userId, String phone, String merchantCode, String bankCode,
			String protocolCode, String userAuthId) {
		final String OP = "ProtocolBindServiceImpl.buildUserPaymentPo";
		UserPaymentPO userP = null;
		try {
			userP = new UserPaymentPO();
			userP.setBankCode(bankCode);
			BankConfigPO bankConfigPO = bankConfigService.queryByBankCode(bankCode);
			userP.setBankName(bankConfigPO.getBankName());
			userP.setCardNo(desensCardNo);
			userP.setCardNoCip(cardNoCip);
			userP.setState(YesNoEnum.YES.getValue());
			userP.setUserId(userId);
			userP.setPhone(phone);
			userP.setPaymentCode(PaymentEnum.FUIOU_PROTOCOL_PAY.getValue());
			userP.setUserAuthId(userAuthId);
			userP.setMerchantCode(merchantCode);
			userP.setProtocolCode(protocolCode);
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("构建用户支付扩展信息异常").toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		return userP;
	}

	/**
	 * 构建请求参数
	 *
	 * @author wangjwy
	 * @date 2018/6/19 10:51
	 * @since 2.2.0
	 * @param userAuthId, protocolCfg
	 * @return com.yyfax.pay.third.model.to.fuiou.FuiouBaseReqVO
	 * @throws Exception
	 */
	private FuiouBaseReqVO buildQueryCardReq(String userAuthId, FuiouProtocolPayExt protocolCfg) {
		final String OP = "ProtocolBindServiceImpl.buildQueryCardReq";
		FuiouBaseReqVO reqVO = new FuiouBaseReqVO();
		ProtocolCardQueryVO xml = new ProtocolCardQueryVO();
		xml.setNerchantCode(protocolCfg.getMerchantId());
		xml.setUserId(userAuthId);
		xml.setVersion(protocolCfg.getVersion());
		StringBuffer sb = new StringBuffer();
		sb.append(xml.getVersion()).append("|").append(xml.getNerchantCode()).append("|").append(xml.getUserId()).append("|")
				.append(protocolCfg.getMerchantSecurit());
		xml.setSign(MD5.MD5Encode(sb.toString()));
		HashMap<String, String> map = Maps.newHashMap();
		map.put(FuiouProtocolPayConstant.MCHNTCD, xml.getNerchantCode());
		try {
			map.put(FuiouProtocolPayConstant.APIFMS,
					DESCoderFUIOU.desEncrypt(xml.toXml(), DESCoderFUIOU.getKeyLength8(protocolCfg.getMerchantSecurit())));
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("协议支付加密请求参数异常").kv("userAuthId", userAuthId).toString(), e);
			throw PayExceptionCode.WARN_UNKNOWN.exp();
		}
		reqVO.setUrl(protocolCfg.getBindQueryUrl());
		reqVO.setConnectTimeOut(protocolCfg.getConnectTimeout());
		reqVO.setReqBody(xml.toXml());
		reqVO.setActReqBody(map);
		return reqVO;
	}

	/**
	 * 处理用户协议卡查询返回
	 *
	 * @author wangjwy
	 * @date 2018/6/15 14:49
	 * @since 2.2.0
	 * @param merchantCode, param, userPaymentPO, respVO, userAuthId
	 * @return com.yyfax.pay.vo.order.ProtocolCardQueryRsp
	 * @throws Exception
	 */
	private ProtocolCardQueryRsp handCardQueryRsp(String merchantCode, ProtocolCardQueryReq param, UserPaymentPO userPaymentPO,
			FuiouProtocolResponseVO respVO, String userAuthId) {
		final String OP = "ProtocolBindServiceImpl.handCardQueryRsp";
		ProtocolCardQueryRsp rsp = new ProtocolCardQueryRsp();
		if (FuiouProtocolResponseVO.TIMEOUT.equals(respVO.getResult())) {
			logger.error(Log.op(OP).msg("请求查询协议卡绑定接口超时").kv("param", param).toString());
			throw PayExceptionCode.WARN_REQ_TIME_OUT.exp();
		}
		String result = respVO.getContent();
		FuiouProCardQueryRsp cardQueryRsp = FuiouProCardQueryRsp.fromXml(result);

		if (FuiouProRspCodeEnum.isToConfirm(cardQueryRsp.getRespCode())) {
			logger.warn(Log.op(OP).msg("富友协议卡查询状态为处理中").kv("param", param).kv("result", result).kv("响应码", cardQueryRsp.getRespCode())
					.kv("描述", cardQueryRsp.getRespDesc()).toString());
			rsp.setState(OrderStateEnum.DEALING.getValue());
			rsp.setDesc(cardQueryRsp.getRespDesc());
			return rsp;
		}
		if (!FuiouProRspCodeEnum.SUCCESS.getValue().equals(cardQueryRsp.getRespCode())) {
			logger.warn(Log.op(OP).msg("富友协议卡查询结果失败").kv("param", param).kv("响应码", cardQueryRsp.getRespCode()).kv("描述", cardQueryRsp.getRespDesc())
					.toString());
			// throw new PayException(PayExceptionCode.QUERY_ERROR.getCode(), cardQueryRsp.getRespDesc());
			rsp.setState(OrderStateEnum.FAIL.getValue());
			rsp.setDesc(cardQueryRsp.getRespDesc());
			return rsp;
		}
		// 更新协议号
		try {
			if (null == userPaymentPO) {
				userPaymentPO = buildUserPaymentPo(DesensitizationUtil.convertBankCard(param.getCardNo()), CryptUtil.encrypt(param.getCardNo()),
						param.getUserId(), param.getPhone(), merchantCode, param.getBankCode(), cardQueryRsp.getProtocolCode(), userAuthId);
				userPaymentService.save(userPaymentPO);
			} else {
				userPaymentPO.setProtocolCode(cardQueryRsp.getProtocolCode());
				userPaymentPO.setState(YesNoEnum.YES.getValue());
				userPaymentDao.update(userPaymentPO);
			}
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("更新用户支付凭证信息异常").kv("userPayment", userPaymentPO).toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		rsp.setState(OrderStateEnum.SUCCESS.getValue());
		rsp.setDesc(cardQueryRsp.getRespDesc());
		rsp.setProtocolCode(cardQueryRsp.getProtocolCode());
		rsp.setCardNo(cardQueryRsp.getCardNo());
		return rsp;
	}

	/**
	 * 构建协议支付请求
	 *
	 * @author wangjwy
	 * @date 2018/6/7 20:01
	 * @since 2.2.0
	 * @param po, protocolConfig
	 * @return com.yyfax.pay.third.model.to.fuiou.FuiouBaseReqVO
	 * @throws Exception
	 */
	private FuiouBaseReqVO buildPayParam(ProtocolOrderDO po, FuiouProtocolPayExt protocolConfig, UserPaymentPO query) {
		final String OP = "ProtocolPayServiceImpl.buildPayParam";
		FuiouBaseReqVO reqVO = new FuiouBaseReqVO();

		ProtocolPayVO xml = new ProtocolPayVO();
		xml.setAmt(po.getAmount());
		xml.setMerchantCode(protocolConfig.getMerchantId());
		xml.setNeedMessage(protocolConfig.getNeedMessage());
		xml.setNotifyUrl(fuiouProtocolPayConstant.getProtocolPayNotifUrl());
		xml.setOrderId(po.getBusiId());
		xml.setProtocolCode(query.getProtocolCode());
		xml.setSignType(protocolConfig.getSignType());
		xml.setType(protocolConfig.getProtocolPayType());
		xml.setUserId(query.getUserAuthId());
		xml.setUserIp(po.getUserIp());
		xml.setVersion(protocolConfig.getVersion());
		StringBuffer sb = new StringBuffer();
		sb.append(xml.getType()).append("|").append(xml.getVersion()).append("|").append(xml.getMerchantCode()).append("|").append(xml.getOrderId())
				.append("|").append(xml.getUserId()).append("|").append(xml.getProtocolCode()).append("|").append(xml.getAmt()).append("|")
				.append(xml.getNotifyUrl()).append("|").append(xml.getUserIp()).append("|").append(protocolConfig.getMerchantSecurit());
		xml.setSign(MD5.MD5Encode(sb.toString()));
		HashMap<String, String> map = Maps.newHashMap();
		map.put(FuiouProtocolPayConstant.MCHNTCD, xml.getMerchantCode());
		try {
			map.put(FuiouProtocolPayConstant.APIFMS,
					DESCoderFUIOU.desEncrypt(xml.toXml(), DESCoderFUIOU.getKeyLength8(protocolConfig.getMerchantSecurit())));
		} catch (Exception e) {
			logger.error(Log.op(OP).msg("协议支付,加密请求失败").toString(), e);
			throw PayExceptionCode.SYS_ERROR.exp();
		}
		reqVO.setChartSet(FuiouProtocolPayConstant.ENCOCING);
		reqVO.setUrl(protocolConfig.getProtocolPayUrl());
		reqVO.setReqBody(xml.toXml());
		reqVO.setActReqBody(map);
		return reqVO;
	}
}
